package control

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"io/ioutil"
	"net/http"
	"smmf/config"
	"smmf/log"
	"smmf/model"
	"time"
)

type Param struct {
}

// HandlerFunc 命令调用
type HandlerFunc func([]byte, Param, int64) (interface{}, int, error)

var (
	_default_cmd_handlers = make(map[string]HandlerFunc)
)

var noAuthMap = make(map[string]bool)

func SetRouter(r *gin.Engine) {
	InitCmd()
	for k, _ := range _default_cmd_handlers {
		r.POST(k, Api)
	}
}

func InitCmd() {
	noAuthMap["/login"] = true
	noAuthMap["/register"] = true
	// 用户类
	user := User{}
	_default_cmd_handlers["/login"] = user.Login
	_default_cmd_handlers["/register"] = user.Register
	_default_cmd_handlers["/userInfo"] = user.UserInfo
}

func Api(c *gin.Context) {
	path := c.Request.URL.Path
	log.Info("path:" + path)
	startTime := time.Now()
	data, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		log.Error("网络错误:", err.Error())
		_, err := c.Writer.Write(encode(config.ERR_READ_HTTP_DATA, "", nil))
		if err != nil {
			log.Error("err:" + err.Error())
		}
		return
	}

	var userId int64
	if _, ok := noAuthMap[path]; !ok {
		token := c.GetHeader("token")
		userToken, err := model.QueryUserToken(token)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			_, err := c.Writer.Write(encode(config.ERR_NOT_LOGIN, "用户未登录,请登录", nil))
			if err != nil {
				log.Error("err:" + err.Error())
			}
			return
		}
		if token != userToken.Token {
			_, err := c.Writer.Write(encode(config.ERR_NOT_LOGIN, "用户未登录,请登录", nil))
			if err != nil {
				log.Error("err:" + err.Error())
			}
			return
		}

		userId, err = ParseToken(token)
		log.Info("userId:,userToken:", userId, userToken.ID)
		if err != nil {
			log.Error("err:", err)
			_, err := c.Writer.Write(encode(config.ERR_NOT_LOGIN, err.Error(), nil))
			if err != nil {
				log.Info("err:" + err.Error())
			}
			return
		}

		if userId != userToken.ID {
			_, err := c.Writer.Write(encode(config.ERR_NOT_LOGIN, "用户未登录,请登录", nil))
			if err != nil {
				log.Error("err:" + err.Error())
			}
			return
		}
		log.Info("userId:,userToken:", userId, userToken.ID)
	}

	param := Param{}
	if f, ok := _default_cmd_handlers[path]; ok {
		res, code, err := f(data, param, userId)
		if err != nil {
			_, err := c.Writer.Write(encode(code, err.Error(), nil))
			if err != nil {
				log.Error("err:", err.Error())
			}
			log.Info("异常接口,userId:%d,path:%s,耗时:%s,in:%s", userId, path, time.Now().Sub(startTime).String(), string(data))
			return
		}
		resp := encode(0, "", res)
		_, err = c.Writer.Write(resp)
		if err != nil {
			log.Error("err:", err.Error())
		}
		log.Info("path:%s,userId:%d,remoteAddr:%s,耗时:%s,in:%s,out:%v", path, userId, c.Request.RemoteAddr, time.Now().Sub(startTime).String(), string(data), string(resp))
		return
	} else {
		_, err = c.Writer.Write(encode(config.FOUND_NOT_ERROR, fmt.Sprintf("接口%s不存在", path), nil))
		if err != nil {
			log.Error("err:", err.Error())
		}
		return
	}
}

func encode(code int, msg string, obj interface{}) []byte {
	if obj == nil {
		obj = NullObj{}
	}
	out := ResultObj{code, msg, obj}
	b, err := json.Marshal(out)
	if err != nil {
		log.Error("Encode json失败:", err.Error())
	}
	return b
}

type NullObj struct {
}

type ResultObj struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func Cors() gin.HandlerFunc {
	return func(context *gin.Context) {
		method := context.Request.Method
		context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
		context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
		context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken,userId")
		context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
		context.Header("Access-Control-Max-Age", "172800")
		context.Header("Access-Control-Allow-Credentials", "false")
		context.Header("Content-Type", "application/json")
		if method == "OPTIONS" {
			context.JSON(http.StatusOK, nil)
		}
		//处理请求
		context.Next()
	}
}
